#include <stdio.h>
#include <dirent.h>
#include "INMP441.h"
#include <string.h>
#include "sdkconfig.h"
#include "esp_check.h"
#include "esp_vfs_fat.h"
#include "driver/i2s_tdm.h"
#include "driver/i2s_std.h"
#include "driver/i2c.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

static const char *TAG = "INMP441";

// INMP441配置参数
#define EXAMPLE_I2S_SAMPLE_RATE     (16000)
#define EXAMPLE_I2S_SAMPLE_BITS     (32)
#define EXAMPLE_I2S_CHAN_NUM        (1)  // INMP441是单声道麦克风
#define EXAMPLE_I2S_MCLK_MULTIPLE   (256)
#define EXAMPLE_I2S_TDM_SLOT_MASK   (I2S_TDM_SLOT0)
#define EXAMPLE_I2S_TDM_FORMAT      (I2S_COMM_FORMAT_STAND_I2S)

// I2S引脚定义 - 使用不同的引脚避免冲突
#define EXAMPLE_I2S_MCK_IO          (-1)   // 使用GPIO1作为MCLK
#define EXAMPLE_I2S_BCK_IO          (GPIO_NUM_1)   // 使用GPIO2作为BCK SCK 
#define EXAMPLE_I2S_WS_IO           (GPIO_NUM_2)   // 使用GPIO3作为WS
#define EXAMPLE_I2S_DI_IO           (GPIO_NUM_42)  // 使用GPIO18作为数据输入

// SD卡配置 - 使用外部初始化的SD卡
#define EXAMPLE_SD_MOUNT_POINT      "/sdcard"
#define EXAMPLE_RECORD_FILE_PATH    "/record.wav"

// 按键配置 - 使用不同的GPIO避免冲突
#define EXAMPLE_BUTTON_GPIO         (GPIO_NUM_0)   // 使用GPIO6作为录音按键
#define EXAMPLE_RECORD_TIME_SEC     (10)           // 录音时长10秒

// 全局变量
static QueueHandle_t button_queue = NULL;
static bool is_recording = false;
static bool sd_card_initialized = false;

// 按键中断处理函数
static void IRAM_ATTR button_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(button_queue, &gpio_num, NULL);
}

// 按键任务
static void button_task(void* arg)
{
    uint32_t io_num;
    while(1) {
        if(xQueueReceive(button_queue, &io_num, portMAX_DELAY)) {
            // 消抖处理
            vTaskDelay(50 / portTICK_PERIOD_MS);
            if(gpio_get_level(io_num) == 0) {  // 按键按下
                if(!is_recording) {
                    ESP_LOGI(TAG, "Button pressed, starting recording");
                    is_recording = true;
                } else {
                    ESP_LOGI(TAG, "Button pressed, stopping recording");
                    is_recording = false;
                }
            }
        }
    }
}

// 初始化按键
static void button_init(void)
{
    // 创建按键队列
    button_queue = xQueueCreate(10, sizeof(uint32_t));
    
    // 配置GPIO
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << EXAMPLE_BUTTON_GPIO),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_NEGEDGE,  // 下降沿触发（按键按下）
    };
    gpio_config(&io_conf);
    
    // 安装GPIO中断服务
    gpio_install_isr_service(0);
    gpio_isr_handler_add(EXAMPLE_BUTTON_GPIO, button_isr_handler, (void*)EXAMPLE_BUTTON_GPIO);
    
    // 创建按键任务
    xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);
}

// INMP441 I2S初始化
static i2s_chan_handle_t inmp441_i2s_init(void)
{
    i2s_chan_handle_t i2s_rx_chan = NULL;  // 定义接收通道句柄
    ESP_LOGI(TAG, "Create I2S receive channel for INMP441");
    
    i2s_chan_config_t i2s_rx_conf = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); // 配置接收通道
    ESP_ERROR_CHECK(i2s_new_channel(&i2s_rx_conf, NULL, &i2s_rx_chan)); // 创建i2s通道

    ESP_LOGI(TAG, "Configure I2S receive channel to TDM mode");
    // 定义接收通道为I2S TDM模式 并配置
    i2s_tdm_config_t i2s_tdm_rx_conf = {  
        .slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(EXAMPLE_I2S_SAMPLE_BITS, I2S_SLOT_MODE_MONO, EXAMPLE_I2S_TDM_SLOT_MASK),
        .clk_cfg  = {
            .clk_src = I2S_CLK_SRC_DEFAULT,
            .sample_rate_hz = EXAMPLE_I2S_SAMPLE_RATE,
            .mclk_multiple = EXAMPLE_I2S_MCLK_MULTIPLE
        },
        .gpio_cfg = {
            .mclk = -1,
            .bclk = EXAMPLE_I2S_BCK_IO,
            .ws   = EXAMPLE_I2S_WS_IO,
            .dout = -1, // INMP441只有ADC能力
            .din  = EXAMPLE_I2S_DI_IO
        },
    };

    ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(i2s_rx_chan, &i2s_tdm_rx_conf)); // 初始化I2S通道为TDM模式

    return i2s_rx_chan;
}

// 检查SD卡是否已初始化
static bool check_sdcard_initialized(void)
{
    // 尝试打开SD卡根目录来检查是否已挂载
    DIR* dir = opendir(EXAMPLE_SD_MOUNT_POINT);
    if (dir != NULL) {
        closedir(dir);
        ESP_LOGI(TAG, "SD card is already mounted and accessible");
        return true;
    } else {
        ESP_LOGE(TAG, "SD card is not accessible. Please ensure tusb_msc_init() is called first");
        return false;
    }
}

// 录音功能
static esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan)
{
    ESP_RETURN_ON_FALSE(i2s_rx_chan, ESP_FAIL, TAG, "invalid i2s channel handle pointer");
    esp_err_t ret = ESP_OK;

    uint32_t byte_rate = EXAMPLE_I2S_SAMPLE_RATE * EXAMPLE_I2S_CHAN_NUM * EXAMPLE_I2S_SAMPLE_BITS / 8;
    uint32_t wav_size = byte_rate * EXAMPLE_RECORD_TIME_SEC;

    const wav_header_t wav_header =
        WAV_HEADER_PCM_DEFAULT(wav_size, EXAMPLE_I2S_SAMPLE_BITS, EXAMPLE_I2S_SAMPLE_RATE, EXAMPLE_I2S_CHAN_NUM);

    ESP_LOGI(TAG, "Opening file %s", EXAMPLE_RECORD_FILE_PATH);
    FILE *f = fopen(EXAMPLE_SD_MOUNT_POINT EXAMPLE_RECORD_FILE_PATH, "w");
    ESP_RETURN_ON_FALSE(f, ESP_FAIL, TAG, "error while opening wav file");

    /* Write wav header */
    ESP_GOTO_ON_FALSE(fwrite(&wav_header, sizeof(wav_header_t), 1, f), ESP_FAIL, err,
                      TAG, "error while writing wav header");

    /* Start recording */
    size_t wav_written = 0;
    static int32_t i2s_readraw_buff[1024];  // INMP441输出32位数据
    ESP_GOTO_ON_ERROR(i2s_channel_enable(i2s_rx_chan), err, TAG, "error while starting i2s rx channel");
    
    ESP_LOGI(TAG, "Recording started...");
    
    while (wav_written < wav_size && is_recording) {
        if(wav_written % byte_rate < sizeof(i2s_readraw_buff)) {
            ESP_LOGI(TAG, "Recording: %"PRIu32"/%ds", wav_written/byte_rate + 1, EXAMPLE_RECORD_TIME_SEC);
        }
        size_t bytes_read = 0;
        /* Read RAW samples from INMP441 */
        ESP_GOTO_ON_ERROR(i2s_channel_read(i2s_rx_chan, i2s_readraw_buff, sizeof(i2s_readraw_buff), &bytes_read,
                          1000 / portTICK_PERIOD_MS), err, TAG, "error while reading samples from i2s");
        /* Write the samples to the WAV file */
        ESP_GOTO_ON_FALSE(fwrite(i2s_readraw_buff, bytes_read, 1, f), ESP_FAIL, err,
                          TAG, "error while writing samples to wav file");
        wav_written += bytes_read;
    }

err:
    i2s_channel_disable(i2s_rx_chan);
    ESP_LOGI(TAG, "Recording done! Flushing file buffer");
    fclose(f);

    return ret;
}

// 录音任务
static void record_task(void *arg)
{
    i2s_chan_handle_t i2s_rx_chan = (i2s_chan_handle_t)arg;
    
    while(1) {
        if(is_recording) {
            ESP_LOGI(TAG, "Starting recording session");
            esp_err_t err = record_wav(i2s_rx_chan);
            if(err == ESP_OK) {
                ESP_LOGI(TAG, "Audio was successfully recorded into "EXAMPLE_RECORD_FILE_PATH);
            } else {
                ESP_LOGE(TAG, "Record failed, "EXAMPLE_RECORD_FILE_PATH" on SD card may not be playable.");
            }
            is_recording = false;  // 录音完成后重置状态
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);  // 短暂延时，避免过度占用CPU
    }
}

// INMP441初始化函数
void inmp441_init(void)
{
    ESP_LOGI(TAG, "Initializing INMP441 recording system");
    
    /* 检查SD卡是否已初始化 */
    if (!check_sdcard_initialized()) {
        ESP_LOGE(TAG, "SD card not available. INMP441 initialization failed.");
        return;
    }
    
    /* 初始化按键 */
    button_init();
    
    /* 初始化I2S接口 */
    i2s_chan_handle_t i2s_rx_chan = inmp441_i2s_init();  
    
    /* 创建录音任务 */
    xTaskCreate(record_task, "record_task", 4096, (void*)i2s_rx_chan, 5, NULL);
    
    ESP_LOGI(TAG, "INMP441 recording system initialized successfully");
    ESP_LOGI(TAG, "Press button to start/stop recording");
}
